import uuid
from django.core.cache import cache
from django.core.mail import send_mail

from rest_framework.viewsets import GenericViewSet,mixins
from rest_framework.decorators import action
from rest_framework.response import Response


from .serializers import UserRegisterSerializer,UserLoginSerializer,UserEmailSerializer,UserSerialiazer,AreaSerializer,AddressSerializer
from.serializers import CartSerializer,SKUSerializer,SkuSpecificationSerializer,CartOrderSkuSerializer
from utils.auth import UserLoginAuthentication
from user.models import User,Area,Address,SKU,GoodsCategory,SKUSpecification,CartModel
from utils.errors import EmailVerifyException
from utils.paginations import GoodsPagination


def get_token(request):
    username = request.data['username']
    token =  uuid.uuid4()
    user_id = User.objects.get(username=username).id
    res = {
    'code': '4000',
    'data': {
         'token': token,
         'username': username,
         'user_id': user_id,
       }
    }
    cache.set(token, user_id, timeout=6000)
    return res


class AddressInfoView(GenericViewSet, mixins.CreateModelMixin,mixins.ListModelMixin, mixins.DestroyModelMixin,mixins.UpdateModelMixin):
    queryset = Address.objects.all()
    authentication_classes = (UserLoginAuthentication,)
    serializer_class = AddressSerializer

    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)
        res = self.get_address(request,instance.id)
        return Response(res)

    def perform_update(self, serializer):
        serializer.save()

    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        instance.is_deleted = True
        instance.save()
        res = {'code': '4000'}
        return Response(res)

    def get_address(self, request, single=0):
        user = request.user
        if single == 0:
            addresses = self.get_queryset().filter(user_id=user.id, is_deleted=False)
        else:
            addresses = self.get_queryset().filter(user_id=user.id, id=single, is_deleted=False)
        defualt_address = user.default_address
        res = {}
        if addresses:
            add_serializer = self.get_serializer(addresses, many=True).data
            res = {
                'data': {
                    'addresses': add_serializer,
                    'default_address': defualt_address.id
                }
            }
        else:
            res['data'] = {}
        res['code'] = '4000'
        return res

    def perform_create(self, serializer):
        serializer.save()

    def create(self, request, *args, **kwargs):
            user_id = request.user.id
            request.data['user'] = user_id
            serializer = self.get_serializer(data=request.data)
            if not serializer.is_valid():
                print(serializer.errors)
                res = {'code': '7001'}
                return Response(res)
            self.perform_create(serializer)
            res = self.get_address(request)
            return Response(res)

    def list(self, request, *args, **kwargs):
        res = self.get_address(request)
        return Response(res)


class UserView(GenericViewSet,mixins.UpdateModelMixin):
    queryset = User.objects.all()

    @action(detail=False, methods=['PUT'], authentication_classes=(UserLoginAuthentication,),serializer_class=UserSerialiazer)
    def address(self, request):
        user = request.user
        serializer = self.get_serializer(user,data=request.data,partial=True)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        res = {'code': '4000'}
        return Response(res)

    @action(detail=False, methods=['POST'], serializer_class=UserRegisterSerializer, url_path='auth/register')
    def register(self, request):
        if request.method == 'POST':
            serializer = self.get_serializer(data=request.data)
            valid = serializer.is_valid(raise_exception=False)
            if not valid:
                res = {'code': serializer.errors.pop('code', '6000')}
                return Response(res)
            serializer.save()
            res = get_token(request)
            return Response(res)


    @action(detail=False, methods=['GET'])
    def username(self, request):
        if User.objects.filter(username=request.query_params['username']).exists():
            res = {'code':'4000', 'data': {'count': 1, }}
            return Response(res)
        res = {'code':'4000', 'msg': '账号唯一', 'data': {'count': 0, }}
        return Response(res)

    @action(detail=False, methods=['GET'])
    def mobiles(self, request):
        if User.objects.filter(mobile=request.GET['mobile']).exists():
            res = { 'code': '4000', 'data': {'count': '1', }}
            return Response(res)
        res = {'code': '4000', 'msg': '号码唯一', 'data': {'count': '0', }}
        return Response(res)

    @action(detail=False,url_path='auth.login', methods=['POST'], serializer_class=UserLoginSerializer)
    def login(self, request):
        serializer = UserLoginSerializer(data=request.data)
        is_valid = serializer.is_valid()
        if not is_valid:
            res = {
                'code': '4001',
            }
            return Response(res)
        else:
            res = get_token(request)
            return Response(res)

    @action(detail=False, methods=['GET'], serializer_class=UserSerialiazer, authentication_classes=(UserLoginAuthentication,))
    def auth(self, request):
        user = request.user
        serializer = self.get_serializer(user)
        res = {
            'code': '4000',
            'data': {
                'user_id': user.id,
                'username': user.username,
                'mobile': user.mobile,
                'email': user.email,
                'email_active': user.email_active,
            }
        }
        return Response(res)

    @action(detail=False, methods=['PATCH'],url_path='auth/emails', authentication_classes=(UserLoginAuthentication,))
    def email(self, request):
        serializer = UserEmailSerializer(data=request.data)
        if not serializer.is_valid():
            code = serializer.errors['non_field_errors'][0].code
            res = {'code': code}
            return Response(res)
        user = request.user
        user.email = serializer.data['email']
        verify_url = user.generate_verify_email_url()
        user.save()
        send_mail('邮箱验证', f'请点击以下链接完成邮箱验证{verify_url}', 'sharkw123@163.com', ('wzk780094245@163.com','2564323263@qq.com'))
        res = {'code': '4001',}
        return Response(res)

    @action(detail=False, url_path='auth/verification', methods=('get',),)
    def verification(self, request):
        user = User.check_verify_email_token(request.query_params['token'])
        if not user:
            raise EmailVerifyException()
        if user.email_active:
            user.email_active = True
            user.save()
            res = {'code': 4100}
        else:
            res ={'code': 4101}
        return Response(res)


class SKUSView(GenericViewSet, mixins.ListModelMixin, mixins.RetrieveModelMixin):
    queryset = SKU.objects.all()
    pagination_class = GoodsPagination
    serializer_class = SKUSerializer

    @action(detail=False,)
    def classifypath(self,request):
        # 拿到分类的对象
        if request.query_params['category_id'] != 'null':
            cat = GoodsCategory.objects.filter(id=request.query_params['category_id']).first()
            cat1 = {
                'url': '#',
                "category":{
                    'name': cat.parent.name
                }
            }
            cat2 = {
                'name':cat.name
            }
            res = {
                'code': '4000',
                'data':{
                    "cat1": cat1,
                    'cat2': cat2
                }
            }
        else:
            res = {'code': '7009'}
        return Response(res)

    @action(detail=True,serializer_class=SKUSerializer)
    def skus(self, request, pk):
        ordering = request.query_params['ordering']
        category = GoodsCategory.objects.filter(id=pk).first()
        skus = self.get_queryset().filter(category_id=category.id).order_by(ordering)

        serializer = self.get_serializer(skus,many=True)

        if skus is not None:
            page_obj = GoodsPagination()

            Paginationgoods = page_obj.paginate_queryset(queryset=skus,request=request,view=self)
            serializer = self.get_serializer(Paginationgoods,many=True)
            res = {

                'code': '4000',
                'data': {
                     'count': len(skus),
                     'results': serializer.data,
            }}
            return Response(res)
        res = {'code': '4000','data':{'results':serializer.data}}
        return Response(res)


class OrderView(GenericViewSet, mixins.ListModelMixin, mixins.CreateModelMixin):
    queryset = CartModel.objects.all()
    serializer_class = CartOrderSkuSerializer
    authentication_classes = (UserLoginAuthentication,)

    @action(detail=False,serializer_class=AddressSerializer)
    def address(self, request):
        user = request.user
        addresses = Address.objects.filter(user=user).all()
        adds_serial = self.get_serializer(addresses, many=True)
        default_address_id = user.default_address_id
        default_address = addresses.filter(id=default_address_id).first()
        add_serial = self.get_serializer(default_address)
        res = {
            'code': '4000',
            'data':{
                'addresses': adds_serial.data,
                'default_address': str(default_address_id),
            }
        }
        return Response(res)

    @classmethod
    def get_freight(cls, skus):
        total_count = 0
        freight = 0
        for sku in skus:
            total_count += sku.c_num
            freight += sku.c_num * sku.sku.price
        return total_count, freight

    def list(self, request, *args, **kwargs):
        user = request.user
        skus = self.get_queryset().filter(user=user, is_select=True).all()
        skus_serial = self.get_serializer(skus, many=True)
        total_count, total_amount = self.get_freight(skus)

        order_info = {
            'skus': skus_serial.data,
            'total_count': total_count,
            'freight': '10',
            'total_amount': total_amount,
        }

        #　订单的缓存信息
        cache_info = order_info.pop('skus')
        order_cache_id = uuid.uuid4()
        cache.set(order_cache_id, order_info, timeout=900)

        res = {
            'code': '4000',
            'data': order_info
        }
        res['data']['order_cache_id'] = order_cache_id
        return Response(res)


class CartView(GenericViewSet, mixins.UpdateModelMixin):
    queryset = CartModel.objects.all()
    authentication_classes = (UserLoginAuthentication,)

    @action(detail=False, serializer_class=CartSerializer, authentication_classes=(UserLoginAuthentication,))
    def cart(self, request):
        user_cart = self.get_queryset().filter(user=request.user).all()
        cart_serializer = self.get_serializer(user_cart, many=True)
        res = {
            'code': '4000',
            'data': {
                'goods': cart_serializer.data
            }
        }
        return Response(res)

    @action(detail=False, methods=['put'], authentication_classes=(UserLoginAuthentication,))
    def select(self,request):
        sku_id = request.data['sku_id']
        count = request.data['count']
        is_select = request.data['selected']
        order = CartModel.objects.filter(sku_id=sku_id, user=request.user).first()
        order.c_num = count
        selected = is_select
        order.is_select = selected
        order.save()
        res = {
            'code': '4000',
            'selected': selected,
        }
        return Response(res)

    @action(detail=False, methods=['put'], authentication_classes=(UserLoginAuthentication,))
    def selection(self, request):
        select_all = request.data['select_all']
        orders = CartModel.objects.filter(user=request.user).all()
        orders.update(is_select=select_all)
        res = {'code':'4000'}
        return Response(res)

    @action(detail=False, methods=['put'],)
    def quantity(self, request):
        sku_id = request.data['sku_id']
        instance = CartModel.objects.filter(user=request.user,sku_id=sku_id).first()
        count = int(request.data['count'])
        if count > 0:
            instance.c_num = count
            instance.save()
            res = {'code': "4000",
                   'data': {
                    "c_num": instance.c_num
                }}
        else:
            res = {
                'code': '8848'
            }
        return Response(res)


class AreaView(GenericViewSet, mixins.RetrieveModelMixin, mixins.DestroyModelMixin):
    queryset = Area.objects.all()
    serializer_class = AreaSerializer


    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        cites = instance.subs.all()
        serializer = self.get_serializer(cites, many=True)
        res = {
            'code': '4000',
            'data': {
                'subs': serializer.data
            }
        }
        return Response(res)


    @action(detail=False,url_path='areas', serializer_class=AreaSerializer,)
    def get_provinces(self, request):
        query_set = self.get_queryset().filter(parent_id=None)
        serializer = self.get_serializer(query_set, many=True)
        res = {
            'code': '4000',
            'data': {
                'provinces': serializer.data
            }
        }
        return Response(res)


class GoodDetailView(GenericViewSet, mixins.RetrieveModelMixin):
    queryset = SKU.objects.all()
    serializer_class = SKUSerializer

    def retrieve(self, request, *args, **kwargs):
        """
        获取商品的细节
        :param request:
        :param args:
        :param kwargs:
        :return:
        """
        instance = self.get_object()  # sku
        specifications = SKUSpecification.objects.filter(sku=instance).all()
        specs_serializer = SkuSpecificationSerializer(specifications, many=True)
        serializer = self.get_serializer(instance)
        specs = self.combine_option(specs_serializer.data)
        res = {
            'code': '4000',
            'data': {
                'sku': serializer.data,
                'specs': specs
            }
        }
        return Response(res)

    @staticmethod
    def combine_option(specs:list):
        specs_beta = []
        types = []
        for spe in specs:
            name = spe['spec'].get('name')
            if name not in types:
                types.append(name)
                item = {
                    'name': name,
                    'options': [
                        {'value': spe['option']['value']}
                    ]
                }
                specs_beta.append(item)
            else:
                index = types.index(name)
                item = {'value': spe['option']['value']}
                specs_beta[index]['options'].append(item)
        return specs_beta

